/** *************************************************************************
 *  @file       TSNInsight.c
 *  @brief	    P2P应用与TSNInsight应用通信的接口
 *  @date		2022/03/29 
 *  @author		junshuai.li
 *  @version	0.0.1 
编写人：李军帅
version0.0.1
1、初始版本			  
****************************************************************************/
#include "net_run.h"




//tsnlight可读地址合法性判断
int tsnlight_read_addr_validity_judgment(u32 base_addr, u16 num)
{
	//判断是否为合法的状态表地址
	if((base_addr >= TSNLIGHT_NODE_VER_ADDR) && ((base_addr+4*num)<= (TSNLIGHT_NODE_VER_ADDR + 4*MAX_NODE_NUM)))
	{
		return 2;
	}
	else if((base_addr >= TSNLIGHT_REG_ADDR) && ((4*num) <= sizeof(tsnlight_reg_data)))
	{
		return 1;
	}
	else
	{
		return -1;
	}

	return -1;
}


void remote_get_tsnlight_data(u8 *remote_pkt, tsnlight_reg_data* register_data, node_ver_table* version_table)
{
	remote_manage_get_res_pkt *tmp_data = NULL;
	unsigned int addr_offset = 0;
	unsigned int base_addr = 0;
	unsigned int num = 0;
	u8* tmp_pkt = NULL;
	
	int ret  = -1;
	int pkt_len = 0;

	tmp_data = (remote_manage_get_res_pkt *)(remote_pkt + UDP_HEAD_LEN);
	base_addr = ntohl(tmp_data->base_addr);
	num = ntohs(tmp_data->num);

	ret = tsnlight_read_addr_validity_judgment(base_addr, num);
	printf("ret=%d\n",ret);

	if(ret == -1) //读地址出错
	{
		tmp_data->num = 0;
		pkt_len = sizeof(remote_manage_get_res_pkt);
	}
	else if(ret == 1)//读寄存器地址空间
	{
		addr_offset = base_addr - TSNLIGHT_REG_ADDR;

		tmp_pkt = (u8*)register_data + 4*addr_offset;
		memcpy((u8*)&(tmp_data->value[0]),tmp_pkt,4*num);
		pkt_len = sizeof(remote_manage_get_res_pkt)+ num*4;
	}
	else if(ret == 2)//读节点版本信息表
	{
		addr_offset = base_addr - TSNLIGHT_NODE_VER_ADDR;

		tmp_pkt = (u8*)version_table + 4*addr_offset;
		memcpy((u8*)&(tmp_data->value[0]),tmp_pkt,4*num);
		pkt_len = sizeof(remote_manage_get_res_pkt)+ num*4;
	}

	tmp_data->header.sub_type = REMOTE_GET_RES;
	
	tsninsight_msg_sender((unsigned char *)tmp_data, pkt_len); //不需要UDP头
}

void remote_set_tsnlight_data(u8 *remote_pkt, tsnlight_reg_data* register_data, node_ver_table* version_table)
{
	remote_manage_set_res_pkt *tmp_data = (remote_manage_set_res_pkt *)(remote_pkt + UDP_HEAD_LEN);

	tmp_data->header.sub_type = REMOTE_SET_RES;
	tmp_data->num = 0; //数目为0表示设置失败

	//只返回报文，没有对数据赋值
	tsninsight_msg_sender((unsigned char *)tmp_data, sizeof(remote_manage_set_res_pkt)); //不需要UDP头
}


//交换机可写地址合法性判断，不合法返回-1，可写寄存器地址返回1，可写FlowID表地址返回2
int switch_write_addr_validity_judgment(u32 base_addr, u16 num)
{
	//可写的寄存器地址
	if( (num == 1) && ((base_addr == SWITCH_RW_PREVENT_BROADCAST_STORM_ADDR) || 
		(base_addr == SWITCH_RW_SCHEDULE_MODE_ADDR) || (base_addr == SWITCH_RW_FORWARD_MODE_ADDR)))
	{
		return 1;
	}

	//可写的FlowID表地址
	if((base_addr >= SWITCH_RW_FLOWID_FORWARD_START_ADDR) && ((base_addr+num-1) <= SWITCH_RW_FLOWID_FORWARD_END_ADDR))
	{
		return 2;
	}

	return -1;
}

//交换机可读地址合法性判断,不合法返回-1，可读写地址返回1，只读地址返回2
int switch_read_addr_validity_judgment(u32 base_addr, u16 num)
{
	int ret;

	ret = switch_write_addr_validity_judgment(base_addr, num);
	
	if((ret == 1) || (ret == 2)) //可读写地址
	{
		return 1;
	}

	//只读地址
	if((base_addr >= SWITCH_RO_START_ADDR) && ((base_addr+num-1) <= SWITCH_RO_END_ADDR))
	{
		return 2;
	}

	return -1;
}

int remote_get_pkt_to_switch_pkt(u8 *pkt)
{
	remote_manage_get_res_pkt *tmp_data = (remote_manage_get_res_pkt *)(pkt + UDP_HEAD_LEN);
	unsigned int tmp_num;
	u8 *switch_data = NULL;    //交换机返回报文中的数据部分
	u8 local_mac[6]={0};
	u16 tmp_mid = htons(tmp_data->mid);
	u16 tmp_data_num = htons(tmp_data->num);
	u32 tmp_base_addr = tmp_data->base_addr;

	bzero(pkt, MAX_PKT_LEN); //清零空间

	//生成mac
	get_hcp_mac_from_mid(local_mac, tmp_mid);
	
	//读数据
	tsmp_get_req(local_mac,tmp_data_num, tmp_base_addr,pkt);

	//读响应
	switch_data = (u8 *)tsmp_get_res(local_mac,tmp_data_num,tmp_base_addr);
	
	if(switch_data != NULL)
	{
		//读回来的数据放到报文中
		memcpy(pkt + sizeof(remote_manage_get_res_pkt),  switch_data, tmp_data_num*4);
	}
	else
	{
		return -1; //没读回来数据
	}

	return 0;
}

void remote_get_switch_data(u8 *remote_pkt)
{
	remote_manage_get_res_pkt tmp_data;//保存北向应用报文中的数据
	int ret=0;
	int pkt_len=0;

	memcpy(&tmp_data, remote_pkt + UDP_HEAD_LEN, sizeof(remote_manage_get_res_pkt));

	//20231007，交换机地址发生了变化，暂时屏蔽掉
	//ret = switch_read_addr_validity_judgment(htonl(tmp_data.base_addr), htons(tmp_data.num));
	
	if(ret == -1)
	{
		printf("switch read only addr error, reject this cmd !\n");
		tmp_data.num = 0;  //数目为0表示读取失败
		pkt_len = sizeof(remote_manage_get_res_pkt);
	}
	else
	{
		ret = remote_get_pkt_to_switch_pkt(remote_pkt); //这里的remote_pkt为交换机返回的数据报文
		if(ret == 0)
		{
			pkt_len = sizeof(remote_manage_get_res_pkt)+(htons)(tmp_data.num)*4;
		}
		else
		{
			tmp_data.num = 0;  //数目为0表示读取失败
			pkt_len = sizeof(remote_manage_get_res_pkt);
		}
	}

	tmp_data.header.sub_type = REMOTE_GET_RES;
	memcpy(remote_pkt, &tmp_data, sizeof(remote_manage_get_res_pkt));
	
	tsninsight_msg_sender(remote_pkt, pkt_len); //不需要UDP头 

	return;
}

int remote_set_pkt_to_switch_pkt(u8 *pkt)
{
	remote_manage_set_req_pkt *tmp_data = (remote_manage_set_req_pkt *)(pkt + UDP_HEAD_LEN);
	u8 local_mac[6]={0};
	u16 tmp_mid = htons(tmp_data->mid);
	u16 tmp_data_num = htons(tmp_data->num);
	u32 tmp_base_addr = tmp_data->base_addr;
	int ret;

	memcpy(pkt + sizeof(tsmp_header)+sizeof(tsmp_set_req_or_get_res_pkt_data), 
			pkt + UDP_HEAD_LEN + sizeof(remote_manage_set_req_pkt), tmp_data_num*sizeof(unsigned int)); //将数据放到指定位置
	bzero(pkt,sizeof(tsmp_header)+sizeof(tsmp_set_req_or_get_res_pkt_data)); //清零空间
	bzero(pkt+sizeof(tsmp_header)+sizeof(tsmp_set_req_or_get_res_pkt_data)+tmp_data_num*sizeof(unsigned int), 
			MAX_PKT_LEN-(sizeof(tsmp_header)+sizeof(tsmp_set_req_or_get_res_pkt_data)+tmp_data_num*sizeof(unsigned int))); //清零空间

	//生成mac
	get_hcp_mac_from_mid(local_mac, tmp_mid);
	
	//写数据
	tsmp_set_req(local_mac,tmp_data_num, tmp_base_addr,pkt);

	//配置验证
	ret = cfg_varify(local_mac,tmp_data_num,tmp_base_addr,pkt);

	//配置验证失败
	if(ret == -1)
	{
		printf("varify remote_set_pkt_to_switch_pkt error! \n");
		return -1;
	}

	return 0;
}



void remote_set_switch_data(u8 *remote_pkt)
{
	remote_manage_set_res_pkt tmp_data; //保存北向应用报文中的数据
	int ret;

	memcpy(&tmp_data, remote_pkt + UDP_HEAD_LEN, sizeof(remote_manage_set_res_pkt));

	ret = switch_write_addr_validity_judgment(htonl(tmp_data.base_addr), htons(tmp_data.num));
	
	if(ret == -1) //写地址有问题
	{
		printf("switch write addr error, reject this cmd !\n");
		tmp_data.num = 0;
	}
	else //写地址没问题
	{
		ret = remote_set_pkt_to_switch_pkt(remote_pkt); //这里的switch_pkt为交换机返回的数据报文
		if(ret == -1)
		{
			printf("switch pkt error, interrupt this cmd !\n");
			tmp_data.num = 0;
		}
	}

	tmp_data.header.sub_type = REMOTE_SET_RES;
	memcpy(remote_pkt, &tmp_data, sizeof(remote_manage_set_res_pkt));
	
	tsninsight_msg_sender(remote_pkt, sizeof(remote_manage_set_res_pkt)); //不需要UDP头 

	return;
}



void remote_pkt_process(u8 *pkt, int pkt_len, tsnlight_reg_data* register_data, node_ver_table* version_table)
{
	remote_manage_pkt *tmp_pkt = (remote_manage_pkt *)(pkt + UDP_HEAD_LEN);

	if(tmp_pkt->header.sub_type == REMOTE_GET_REQ)
	{
		if((htons)(((remote_manage_get_req_pkt *)tmp_pkt)->taskid) == REMOTE_TASK_TSNLIGHT)
		{
			//获取tsnlight地址空间的数据
			printf("*********************** get TSNLight data *************************************\n");
			remote_get_tsnlight_data(pkt, register_data, version_table);
		}
		else if((htons)(((remote_manage_get_req_pkt *)tmp_pkt)->taskid) == REMOTE_TASK_SWITCH)
		{
			//获取TSN交换机的数据
			printf("*********************** get TSNSwitch data ************************************\n");
			remote_get_switch_data(pkt);
		}
	}
	else if(tmp_pkt->header.sub_type == REMOTE_SET_REQ)
	{
		if((htons)(((remote_manage_set_req_pkt *)tmp_pkt)->taskid) == REMOTE_TASK_TSNLIGHT)
		{
			//设置tsnlight地址空间的数据
			printf("*********************** set TSNLight data *************************************\n");
			remote_set_tsnlight_data(pkt, register_data, version_table);
		}
		else if((htons)(((remote_manage_set_req_pkt *)tmp_pkt)->taskid) == REMOTE_TASK_SWITCH)
		{
			//设置TSN交换机的数据
			printf("*********************** set TSNSwitch data ************************************\n");
			remote_set_switch_data(pkt);
		}
	}
	else
	{
		printf("recv unknow pkt type!\n");
	}

	return;
}


int net_run_handle(node_mid_table* table,u32 sync_mode, 
					tsnlight_reg_data* register_data, node_ver_table* version_table)
{
	u16 pkt_len  = 1;//报文长度
	u8 *pkt = NULL; //报文的指针
	int ret = 0;
	//申请空间，用于构造配置报文
	u8 *cfg_pkt = NULL;

	cfg_pkt = (u8 *)malloc(MAX_PKT_LEN);
	if(NULL == cfg_pkt)
	{
		printf("net_run,malloc buf fail\n");
		return -1;
	}

	bzero(cfg_pkt,MAX_PKT_LEN);

	
	
	while(1)
	{
		
		//每次获取一个报文
		pkt = tsmp_pkt_receive_dispatch_1(&pkt_len);

#if 0
		generate_debug_pkt(pkt, &pkt_len); //调试用的
		printf("1.下面是北向应用报文!!!!!!!!!\n");
		cnc_pkt_print(pkt,pkt_len);
#endif

		if(pkt == NULL)
		{
			continue;
		}
		else if(pkt[12] == 0xff && pkt[13] == 0x01)//判断是否为TSMP报文，以太网类型为0xff01
		{
			continue;
		}
		else
			//远程报文处理
			remote_pkt_process(pkt, pkt_len, register_data, version_table);
	}

	free(cfg_pkt);

	return 0;
}



